#include "game.c"

void timer0_init()
{
    // Timer0 模式1
    TMOD &= 0xF0;
    TMOD |= 0x01;

    // 启动
    TR0 = 1;
    // 使能中断
    ET0 = 1;
    // 开总中断
    EA = 1;
    // Timer0中断高优先级，和串口同时开启的时候，需要设置
    PT0 = 1;
}

/**
 * 是否能够进入中断，使能之后，可以进入中断函数
 */
void timer0_isr_enable()
{
    ET0 = 1;
}

/**
 * 禁止进入中断函数，但是TH0和TL0还会正常自增
 */
void timer0_isr_disable()
{
    ET0 = 0;
}

uchar continuously_button_press(uchar preesed_btn)
{
    // 首次按下
    if (game_pressed_button != preesed_btn)
    {
        game_pressed_button = preesed_btn;
        game_button_continuous_count = 0;
        game_pressed_button_acceleration = 1;
        return preesed_btn;
    }

    // 注意unsigend 类型变量不能比较 < 0 因为unsugend 最小是0，没有负数
    // 持续按下进入到这里
    if (game_button_continuous_count < BTN_COUNT_DOWN)
    {
        game_button_continuous_count += game_pressed_button_acceleration;
        // 这里没有修改game_button_continuous_times 说明按键还没有抬起来，保持原样
        return PRESSED_NONE;
    }
    game_button_continuous_count = 0;
    // 提供一个连续进入加速功能，连续进入到这里，每次的延迟变低，返回按钮的频率变高
    if (game_pressed_button_acceleration <= PRESS_ACCELERATION_MAX)
    {
        game_pressed_button_acceleration *= 2;
    }
    return preesed_btn;
}

/**
 * 针对：开始，暂停，方向下
 * 方法被调用，如果有按键被按下，等到按键抬起后返回按键对应数字
 * 如果没有按键被按下，返回0
 *
 * 针对：方向左、右、上（变形）
 * 当方法连续被调用的时候，如果同一个按键持续被按下。
 * 调用呈现 X000000X000000X的间隔性返回按键对应数字
 */
uchar pressed_button()
{
    if (BTN_START == 0)
    {
        while (BTN_START == 0)
            ;
        game_pressed_button = PRESSED_START;
        game_button_continuous_count = 0;
        return PRESSED_START;
    }

    if (BTN_PAUSE == 0)
    {
        while (BTN_PAUSE == 0)
            ;
        game_pressed_button = PRESSED_PAUSE;
        game_button_continuous_count = 0;
        return PRESSED_PAUSE;
    }

    if (BTN_UP == 0)
    {
        while (BTN_UP == 0)
            ;
        game_pressed_button = PRESSED_UP;
        game_button_continuous_count = 0;
        return PRESSED_UP;
    }

    if (BTN_DOWN == 0)
    {
        while (BTN_DOWN == 0)
            ;
        game_pressed_button = PRESSED_DOWN;
        game_button_continuous_count = 0;
        return PRESSED_DOWN;
    }

    if (BTN_LEFT == 0)
    {
        return continuously_button_press(PRESSED_LEFT);
    }

    if (BTN_RIGHT == 0)
    {
        return continuously_button_press(PRESSED_RIGHT);
    }

    game_pressed_button_acceleration = 1;
    game_pressed_button = PRESSED_NONE;
    game_button_continuous_count = 0;
    return PRESSED_NONE;
}

void wait_until_button_pressed(uchar target_button)
{
    while (pressed_button() != target_button)
        ;
}

void until_speed_confirm()
{
    uchar btn = pressed_button();
    while (btn != PRESSED_START)
    {
        if (btn == PRESSED_RIGHT)
        {
            game_speed = (game_speed + 1) % 10;
            display_speed_num_choosing();
        }
        else if (btn == PRESSED_LEFT)
        {
            game_speed = (game_speed - 1 + 10) % 10;
            display_speed_num_choosing();
        }
        btn = pressed_button();
    }
}

void tetris_play()
{
    while (game_stage == GAME_STAGE_PLAY)
    {
        switch (pressed_button())
        {
        case PRESSED_LEFT:
            timer0_isr_disable();
            game_zone_remove_shape();
            if (game_check_shape_placed(game_shape.x - 1, game_shape.y, game_shape.shape))
            {
                game_shape.x--;
            }
            game_zone_add_shape();
            display_game_zone();
            timer0_isr_enable();
            break;
        case PRESSED_RIGHT:
            timer0_isr_disable();
            game_zone_remove_shape();
            if (game_check_shape_placed(game_shape.x + 1, game_shape.y, game_shape.shape))
            {
                game_shape.x++;
            }
            game_zone_add_shape();
            display_game_zone();
            timer0_isr_enable();
            break;
        case PRESSED_UP:
            timer0_isr_disable();
            game_rand_seed_update();
            game_zone_remove_shape();
            if (game_check_shape_placed(game_shape.x, game_shape.y,
                                        TETRIS_SHAPES[game_shape.shape_type][(game_shape.shape_pos + 1) % 4]))
            {
                game_shape.shape_pos = (game_shape.shape_pos + 1) % 4;
                game_shape.shape = TETRIS_SHAPES[game_shape.shape_type][game_shape.shape_pos];
            }
            game_zone_add_shape();
            display_game_zone();
            timer0_isr_enable();
            break;
        case PRESSED_DOWN:
            timer0_isr_disable();
            game_zone_remove_shape();
            while (game_check_shape_placed(game_shape.x, game_shape.y + 1, game_shape.shape))
            {
                game_shape.y++;
            }
            game_zone_add_shape();
            if (game_eliminate_lines() > 0)
            {
                display_speed_num_playing();
                display_score_num();
            }
            game_next_shape();
            game_show_next_shape();
            game_zone_add_shape();
            display_game_zone();
            timer0_isr_enable();
            break;
        case PRESSED_PAUSE:
            timer0_isr_disable();
            display_pause_chars();
            wait_until_button_pressed(PRESSED_PAUSE);
            display_hide_pause_chars();
            timer0_isr_enable();
            break;
        default:
            break;
        }
    }
}

// 中断只在游戏进行中，刷新显示画面
// 处理下落、消除行、生成新方块的逻辑
void timer0_ISR() interrupt 1
{
    if (game_stage != GAME_STAGE_PLAY)
    {
        return;
    }

    if (game_frame_count < GAME_FRAME_TOTAL - (game_speed << 1))
    {
        game_frame_count++;
    }
    else
    {
        game_frame_count = 0;
        // 注意这里是 y+1，先判断下面能不能下落，可以的话就下落
        game_zone_remove_shape();
        if (game_check_shape_placed(game_shape.x, game_shape.y + 1, game_shape.shape))
        {
            game_shape.y++;
            game_zone_add_shape();
        }
        else
        {
            game_zone_add_shape();
            if (game_eliminate_lines() > 0)
            {
                display_speed_num_playing();
                display_score_num();
            }

            game_next_shape();
            game_show_next_shape();
            if (!game_check_shape_placed(game_shape.x, game_shape.y, game_shape.shape))
            {
                game_stage = GAME_STAGE_OVER;
            }
            else
            {
                game_zone_add_shape();
            }
        }
        display_game_zone();
    }
}

void main(void)
{
    uart_init();
    display_init();
    timer0_init();
    while (1)
    {
        switch (game_stage)
        {
        case GAME_STAGE_BEGIN:
            game_data_init();
            display_clear();
            display_start_pic();
            wait_until_button_pressed(PRESSED_START);
            game_rand_seed_update();
            game_stage = GAME_STAGE_SPEED_CHOOSE;
            break;
        case GAME_STAGE_SPEED_CHOOSE:
            display_clear();
            display_speed_chose();
            until_speed_confirm();
            display_clear();
            display_game_boundary();
            display_score_num();
            display_score_chars();
            display_speed_chars_playing();
            display_speed_num_playing();
            display_icon_words();
            game_init_shape();
            game_zone_add_shape();
            game_show_next_shape();
            display_game_zone();
            game_stage = GAME_STAGE_PLAY;
            break;
        case GAME_STAGE_PLAY:
            tetris_play();
            break;
        case GAME_STAGE_OVER:
            display_game_over();
            wait_until_button_pressed(PRESSED_START);
            game_stage = GAME_STAGE_BEGIN;
            break;
        default:
            break;
        }
    }
}